import 'dart:typed_data';

import 'package:bluetooth_protocols_plugin/library.dart';

import '../enum/file_handle_error_type.dart';
import '../tools/byte_builder.dart';

// 文件操作响应基类
abstract class FileResponseBase {
  // 错误类型
  FileHandleErrorType? errorType = FileHandleErrorType.otherError;

  // 文件修改时间
  int? _modifiedTime;

  // 是否成功
  bool get isSuccess => errorType == FileHandleErrorType.success;

  // 获取文件修改时间
  DateTime? get modifiedDate {
    if (_modifiedTime == null) return null;
    final builder = ByteBuilder();
    builder.addUint32(_modifiedTime!);
    RecordDate date = RecordDate.fromBytes(builder.toBytes());
    return date.toDateTime();
  }
}

// 打开文件响应
class OpenFileResponse extends FileResponseBase {
  // 文件句柄
  int fileHandle = -1;

  // 已存在的文件大小
  int existingFileSize = 0;

  // 已存在的文件CRC32
  int existingFileCrc32 = 0;

  // 文件修改时间
  DateTime? modifiedDate;

  OpenFileResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 10) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 文件句柄
    fileHandle = byteData.getUint8(0);
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(1));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
    // 文件大小
    existingFileSize = byteData.getUint32(2, Endian.little);
    // 文件校验码
    existingFileCrc32 = byteData.getUint32(6, Endian.little);
    // 文件修改时间
    if (byteData.lengthInBytes >= 14) {
      _modifiedTime = byteData.getUint32(10, Endian.little);
    }
  }
}

// 读取文件响应
class ReadFileResponse extends FileResponseBase {
  // 文件句柄
  int fileHandle = -1;

  // 偏移地址
  int fileOffset = -1;

  // 读应答数据（0-256 Bytes）
  List<int> readRspData = [];

  ReadFileResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 6) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 文件句柄
    fileHandle = byteData.getUint8(0);
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(1));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
    // 偏移地址
    fileOffset = byteData.getUint32(2, Endian.little);
    // 读应答数据
    readRspData = bytes.sublist(6);
  }
}

// 写文件响应
class WriteFileResponse extends FileResponseBase {
  // 文件句柄
  int fileHandle = -1;

  // 写入的数据长度
  int writeLength = 0;

  WriteFileResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 3) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 文件句柄
    fileHandle = byteData.getUint8(0);
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(1));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
    // 写入的长度
    writeLength = byteData.getUint8(2);
  }
}

// 校验读取文件响应
class VerifyReadFileResponse extends FileResponseBase {
  // 文件句柄
  int fileHandle = -1;

  // 文件总大小
  int fileSize = 0;

  // 指定偏移地址
  int fileOffset = 0;

  // 指定偏移地址处的校验码
  int offsetCrc32 = 0;

  VerifyReadFileResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 14) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 文件句柄
    fileHandle = byteData.getUint8(0);
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(1));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
    // 文件大小
    fileSize = byteData.getUint32(2, Endian.little);
    // 文件偏移地址
    fileOffset = byteData.getUint32(6, Endian.little);
    // 指定偏移地址处的校验码
    offsetCrc32 = byteData.getUint32(10, Endian.little);
  }
}

// 校验写入文件响应
class VerifyWriteFileResponse extends FileResponseBase {
  // 文件句柄
  int fileHandle = -1;

  // 文件校验（CRC32）
  int fileCrc32 = 0;

  // 校验结果（0: 校验错误，1: 校验通过）
  bool fileCrc32Success = false;

  VerifyWriteFileResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 3) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 文件句柄
    fileHandle = byteData.getUint8(0);
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(1));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
    // 校验结果
    fileCrc32Success = byteData.getUint8(2) == 1;
  }
}

// 关闭文件响应
class CloseFileResponse extends FileResponseBase {
  // 文件句柄
  int fileHandle = -1;

  CloseFileResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 2) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 文件句柄
    fileHandle = byteData.getUint8(0);
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(1));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
  }
}

// 读取文件信息响应
class ReadFileInfoResponse extends FileResponseBase {
  // 文件大小
  int fileSize = -1;

  // 文件校验码
  int fileCrc32 = 0;

  // 文件修改时间
  DateTime? modifiedDate;

  ReadFileInfoResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 15) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(0));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
    // 文件大小
    fileSize = byteData.getUint32(1, Endian.little);
    // 文件校验码
    fileCrc32 = byteData.getUint32(5, Endian.little);
    // 文件修改时间
    _modifiedTime = byteData.getUint32(9, Endian.little);
  }
}

// 删除文件响应
class DeleteFileResponse extends FileResponseBase {
  DeleteFileResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 1) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(0));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
  }
}

// 重命名文件响应
class RenameFileResponse extends FileResponseBase {
  RenameFileResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 1) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(0));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
  }
}

// 获取文件列表响应
class GetFileListResponse extends FileResponseBase {
  // 目录树剩余叶子节点数目（Uint16）
  int remainingLeafNodeCount = 0;

  // 文件组 1 包含的文件数（Uint8）
  int fileCount = 0;

  // 文件列表
  List<FileItemInfo> fileItems = [];

  GetFileListResponse.fromBytes(Uint8List bytes) {
    if (bytes.length < 3) {
      throw Exception('$runtimeType 数据长度不足');
    }
    ByteData byteData = bytes.buffer.asByteData();
    // 错误码
    errorType = FileHandleErrorType.getTypeByNum(byteData.getUint8(0));
    if (errorType != FileHandleErrorType.success) {
      throw Exception('${errorType?.name}');
    }
    // 目录树剩余叶子节点数目
    remainingLeafNodeCount = byteData.getUint16(1, Endian.little);
    // 文件组 1 包含的文件数
    fileCount = byteData.getUint8(3);
    // 文件列表
    int offset = 4;
    for (int i = 0; i < fileCount; i++) {
      if (bytes.length < offset + 9) {
        throw Exception('$runtimeType 数据长度不足');
      }
      int nameLength = byteData.getUint32(offset, Endian.little);
      String name = String.fromCharCodes(
          bytes.sublist(offset + 4, offset + 4 + nameLength - 1));
      int length = byteData.getUint32(offset + 4 + nameLength, Endian.little);
      int modifiedTime =
          byteData.getUint32(offset + 8 + nameLength, Endian.little);
      DateTime? modifiedDate;
      {
        final builder = ByteBuilder();
        builder.addUint32(modifiedTime);
        RecordDate date = RecordDate.fromBytes(builder.toBytes());
        modifiedDate = date.toDateTime();
      }
      fileItems.add(FileItemInfo(
        fileNameLength: nameLength,
        fileName: name,
        fileLength: length,
        modifiedDate: modifiedDate,
      ));
      offset += 12 + nameLength;
    }
  }
}

// 文件项信息
class FileItemInfo {
  // 文件名长度 Uint32（含末尾‘\0’）
  int? fileNameLength;

  // 文件名
  String? fileName;

  // 文件长度 Uint32
  int? fileLength;

  // 文件修改日期
  DateTime? modifiedDate;

  FileItemInfo({
    this.fileNameLength,
    this.fileName,
    this.fileLength,
    this.modifiedDate,
  });
}
